﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.Timers;
using System.Xml;
using System.Xml.Linq;
using System.IO;
//using System.Math;


using SGP;




namespace ParticlTool
{

    public struct CParticle
    {

        float m_CurrLifeTime;

        public float CurrLifeTime
        {
            get { return m_CurrLifeTime; }
            set { m_CurrLifeTime = value; }
        }

        PointF velocity;

        public PointF Velocity
        {
            get { return velocity; }
            set { velocity = value; }
        }

        float x;

        public float X
        {
            get { return x; }
            set { x = value; }
        }
        float y;

        public float Y
        {
            get { return y; }
            set { y = value; }
        }
    }

    public partial class Form1 : Form
    {
        //Elapsed time math stuff
        static long AppTime;
        //Random number generator.
        static Random randGen = new Random();
        //unrelated
        bool looping = true;
        public bool Looping
        {
            get { return looping; }
            set { looping = value; }
        }

        bool mouseIsDown;

        //Texture FilePath name
        string textureName;

        //Particle looping stuff
        int iterations;

        //all my particles
        List<CParticle> emitter = new List<CParticle>();

        //Respawn timer.
        float respawn = 0.0f;

        //lookup list for my texture.
        List<int> textureIndex = new List<int>();

        //Color for particle
        Color startColor = Color.Blue;
        Color endColor = Color.Red;

        //elapsedtime
        Stopwatch _delta = Stopwatch.StartNew();
        //Timer elapsedTime = new System.Timers.Timer(2000);


        //Emitter Position
        PointF emitterPoint = new PointF(200.0f, 200.0f);

        //Adding test particle, should be done in update;


        CSGP_Direct3D d3d = CSGP_Direct3D.GetInstance();
        CSGP_TextureManager TM = CSGP_TextureManager.GetInstance();

        public Form1()
        {
            InitializeComponent();
            d3d.Initialize(panel1, true);

            TM.Initialize(d3d.Device, d3d.Sprite);
            comboBox1.SelectedIndex = comboBox1.FindStringExact("point");
            //working on elapsed time.
            AppTime = _delta.ElapsedMilliseconds;
            //dumping dummy value.
            randGen.Next((int)numericUpDown3.Value, (int)numericUpDown4.Value);
            respawn = randGen.Next((int)numericUpDown3.Value, (int)numericUpDown4.Value);

            CParticle testPart = new CParticle();
            testPart.X = emitterPoint.X;
            testPart.Y = emitterPoint.Y;
            emitter.Add(testPart);

        }
        public void Render()
        {
            d3d.Clear(panel1, Color.Black);
            d3d.DeviceBegin();
            d3d.SpriteBegin();
            if (textureIndex.Count != 0)
            {

                for (int i = 0; i < emitter.Count(); i++)
                {
                    TM.Draw(textureIndex[0],
                        (int)emitter[i].X - (int)((TM.GetTextureWidth(textureIndex[0]) / 2) * (float)numericUpDown7.Value),
                        (int)emitter[i].Y - (int)((TM.GetTextureHeight(textureIndex[0]) / 2) * (float)numericUpDown7.Value),
                        (float)numericUpDown7.Value,
                        (float)numericUpDown7.Value,
                        Rectangle.Empty, 0.0f, 0.0f, 0.0f, startColor);

                }
                TM.Draw(textureIndex[0], (int)emitterPoint.X - TM.GetTextureWidth(textureIndex[0]) / 2, (int)emitterPoint.Y - TM.GetTextureHeight(textureIndex[0]) / 2);

            }
            d3d.SpriteEnd();
            d3d.DeviceEnd();
            d3d.Present();



        }
        public void Update()
        {
            long now = _delta.ElapsedMilliseconds;
            float elapsedTime = (now - AppTime) / 10000.0f;


            if (elapsedTime > 0.125f)
                elapsedTime = 0.125f;
            //reduce timers




            if (textureIndex.Count != 0)
            {
                respawn -= elapsedTime;

                if (respawn < 0)
                {


                    if (numericUpDown28.Value > emitter.Count)
                    {
                        //Add a particle, reset spawn timer.
                        CParticle tempPar = new CParticle();

                        tempPar.X = emitterPoint.X;
                        tempPar.Y = emitterPoint.Y;
                        tempPar.Velocity = new PointF(0.0f, 1.0f);



                        if (numericUpDown2.Value < numericUpDown1.Value)
                        {
                            numericUpDown1.Value = numericUpDown2.Value;
                        }

                        //making the lifetime a float value
                        tempPar.CurrLifeTime = (float)(randGen.Next((int)numericUpDown1.Value, (int)numericUpDown2.Value)) + (float)randGen.NextDouble();

                        if (numericUpDown26.Value < numericUpDown17.Value)
                        {
                            numericUpDown17.Value = numericUpDown26.Value;
                        }

                        float angle = (float)(randGen.Next((int)numericUpDown17.Value, (int)numericUpDown26.Value)) + (float)randGen.NextDouble();


                        //get my rotated velocity.
                        PointF tempFuncVec = Rotate((float)(Math.PI / 180.0f) * angle,
                           tempPar.Velocity.X,
                           tempPar.Velocity.Y);


                        //Set Velocity
                        tempPar.Velocity = tempFuncVec;
                        if (iterations >= numericUpDown28.Value)
                        { }
                        else
                        {
                            emitter.Add(tempPar);
                        }
                        if (checkBox1.Checked == false)
                        {
                            iterations++;
                        }
                        if (numericUpDown4.Value < numericUpDown3.Value)
                        {
                            numericUpDown3.Value = numericUpDown4.Value;
                        }
                        respawn = randGen.Next((int)numericUpDown3.Value, (int)numericUpDown4.Value);

                    }
                }

                for (int i = 0; i < emitter.Count(); i++)
                {
                    CParticle temp = emitter[i];
                    temp.CurrLifeTime -= elapsedTime;
                    temp.X += temp.Velocity.X * (float)numericUpDown27.Value * elapsedTime;
                    temp.Y += temp.Velocity.Y * (float)numericUpDown27.Value * elapsedTime;
                    emitter[i] = temp;

                    if (emitter[i].CurrLifeTime < 0)
                    {
                        emitter.RemoveAt(i);
                    }
                }
            }


        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            looping = false;
        }

        private void panel1_Resize(object sender, EventArgs e)
        {
            d3d.Resize(panel1, panel1.ClientSize.Width, panel1.ClientSize.Height, true);
        }

        private void toolStripLabel1_Click(object sender, EventArgs e)
        {

        }

        private void label6_Click(object sender, EventArgs e)
        {

        }

        private void numericUpDown12_ValueChanged(object sender, EventArgs e)
        {

        }

        private void loadTextureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog watevs = new OpenFileDialog();
            watevs.InitialDirectory = System.IO.Path.GetFullPath("Resources\\Particles");
            watevs.Filter = "PNG Files (*.png*)|*.png*";

            if (DialogResult.OK == watevs.ShowDialog())
            {
                //looading into FileName.

                if(textureIndex.Count == 0)
                {
                textureIndex.Add(TM.LoadTexture(watevs.FileName));
                }
                else
                {
                    TM.UnloadTexture(0);
                    textureIndex.Add(TM.LoadTexture(watevs.FileName));
                }
                textureName = watevs.FileName;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ColorDialog watevs = new ColorDialog();


            if (DialogResult.OK == watevs.ShowDialog())
            {
                //looading into FileName.
                startColor = watevs.Color;

            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ColorDialog watevs = new ColorDialog();


            if (DialogResult.OK == watevs.ShowDialog())
            {
                //looading into FileName.
                endColor = watevs.Color;

            }
        }

        private PointF Rotate(float radians, float x, float y)
        {
            float sin = (float)Math.Sin(radians);
            float cos = (float)Math.Cos(radians);

            float newX = (cos * x) - (sin * y);
            y = (sin * x) + (cos * y);
            x = newX;

            PointF temp = new PointF();
            temp.X = x;
            temp.Y = y;

            return temp;
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox1.Checked == true)
            {
                iterations = 0;
            }
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {

            
            ////Sets to Resources/Map if not already there
            //if (Directory.Exists("..//..//NationalBombBallLeague//NationalBombBallLeague//Resources//Particles"))
            //    Directory.SetCurrentDirectory("..//..//NationalBombBallLeague//NationalBombBallLeague//Resources//Particles");

            //Save a map in xml here
            SaveFileDialog saveBox = new SaveFileDialog();
            saveBox.InitialDirectory = System.IO.Path.GetFullPath("Resources\\Particles");
            saveBox.Filter = "XML Files(*.xml*)|*.xml*";
            saveBox.DefaultExt = ".xml";

            //saveBox.InitialDirectory = Directory.GetCurrentDirectory();

            if (saveBox.ShowDialog() == DialogResult.OK)
            {
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;

                XmlWriter writer = XmlWriter.Create(saveBox.FileName, settings);

                //Begins the document
                writer.WriteStartDocument();

                //Establishes root element
                writer.WriteStartElement("Emitter");

                if (textureIndex.Count() != 0)
                {
                    writer.WriteStartElement("Texture");
                    writer.WriteString(textureName.ToString());
                    writer.WriteEndElement();

                }
                else
                {
                    writer.WriteStartElement("Texture");
                    writer.WriteString(null);
                    writer.WriteEndElement();
                }
                writer.WriteStartElement("NumberOfParticles");
                writer.WriteString(numericUpDown28.Value.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("Loop");
                if (checkBox1.Checked)
                {
                    writer.WriteString("1");
                }
                else
                {
                    writer.WriteString("0");
                }

                writer.WriteEndElement();

                writer.WriteStartElement("MinLifetime");
                writer.WriteString(numericUpDown1.Value.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("MaxLifetime");
                writer.WriteString(numericUpDown2.Value.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("MinSpawnDelay");
                writer.WriteString(numericUpDown3.Value.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("MaxSpawnDelay");
                writer.WriteString(numericUpDown4.Value.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("StartScale");
                writer.WriteString(numericUpDown7.Value.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("EndScale");
                writer.WriteString(numericUpDown8.Value.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("StartRotation");
                writer.WriteString(numericUpDown9.Value.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("EndRotation");
                writer.WriteString(numericUpDown10.Value.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("StartColor");
                writer.WriteAttributeString("A", startColor.A.ToString());
                writer.WriteAttributeString("R", startColor.R.ToString());
                writer.WriteAttributeString("G", startColor.G.ToString());
                writer.WriteAttributeString("B", startColor.B.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("EndColor");
                writer.WriteAttributeString("A", endColor.A.ToString());
                writer.WriteAttributeString("R", endColor.R.ToString());
                writer.WriteAttributeString("G", endColor.G.ToString());
                writer.WriteAttributeString("B", endColor.B.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("MinVelocityRotation");
                writer.WriteString(numericUpDown17.Value.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("StartMagnitude");
                writer.WriteString(numericUpDown18.Value.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("MaxVelocityRotation");
                writer.WriteString(numericUpDown26.Value.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("EndMagnitude");
                writer.WriteString(numericUpDown27.Value.ToString());
                writer.WriteEndElement();

                writer.WriteStartElement("EmitterType");
                writer.WriteString(comboBox1.SelectedItem.ToString());
                writer.WriteEndElement();


                writer.WriteEndElement();

                //Ends document
                writer.WriteEndDocument();
                writer.Flush();
                writer.Close();
            }

        }

        private void numericUpDown2_ValueChanged(object sender, EventArgs e)
        {

            int tempMin = (int)numericUpDown1.Value;
            int tempMax = (int)numericUpDown2.Value;
            int delta = tempMax - tempMin;
            if (numericUpDown2.Value < numericUpDown1.Value)
            {
                numericUpDown1.Value = numericUpDown2.Value;


            }
        }

        private void loadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ////Sets to Resources/Map if not already there
            //if (Directory.Exists("..//..//..//..//..//..//NationalBombBallLeague//NationalBombBallLeague//Resources//Particles"))
            //    Directory.SetCurrentDirectory("..//..//..//..//..//..//NationalBombBallLeague//NationalBombBallLeague//Resources//Particles");

            OpenFileDialog openBox = new OpenFileDialog();
            openBox.InitialDirectory = System.IO.Path.GetFullPath("Resources\\Particles");
            openBox.Filter = "XML Files(*.xml*)|*.xml*";
           // openBox.InitialDirectory = Directory.GetCurrentDirectory();

            if (DialogResult.OK == openBox.ShowDialog())
            {


                XmlTextReader reader = new XmlTextReader(openBox.FileName);

                if (reader.Read())
                {
                    reader.ReadToFollowing("Emitter");
                    reader.ReadToFollowing("Texture");
                    textureName = reader.ReadElementContentAsString();
                    textureIndex.Add(TM.LoadTexture(textureName));

                    reader.ReadToFollowing("NumberOfParticles");
                    numericUpDown28.Value = Int32.Parse(reader.ReadElementContentAsString());

                    reader.ReadToFollowing("Loop");
                    checkBox1.Checked = reader.ReadElementContentAsBoolean();


                    reader.ReadToFollowing("MinLifetime");
                    numericUpDown1.Value = Int32.Parse(reader.ReadElementContentAsString());


                    reader.ReadToFollowing("MaxLifetime");
                    numericUpDown2.Value = Int32.Parse(reader.ReadElementContentAsString());


                    reader.ReadToFollowing("MinSpawnDelay");
                    numericUpDown3.Value = Int32.Parse(reader.ReadElementContentAsString());


                    reader.ReadToFollowing("MaxSpawnDelay");
                    numericUpDown4.Value = Int32.Parse(reader.ReadElementContentAsString());

                    reader.ReadToFollowing("StartScale");
                    numericUpDown7.Value = decimal.Parse(reader.ReadElementContentAsString());

                    reader.ReadToFollowing("EndScale");
                    numericUpDown8.Value = decimal.Parse(reader.ReadElementContentAsString());

                    reader.ReadToFollowing("StartRotation");
                    numericUpDown9.Value = Int32.Parse(reader.ReadElementContentAsString());


                    reader.ReadToFollowing("EndRotation");
                    numericUpDown10.Value = Int32.Parse(reader.ReadElementContentAsString());


                    reader.ReadToFollowing("StartColor");
                    reader.MoveToFirstAttribute();

                    int A = Int32.Parse(reader.Value);
                    reader.MoveToNextAttribute();
                    int R = Int32.Parse(reader.Value);
                    reader.MoveToNextAttribute();
                    int G = Int32.Parse(reader.Value);
                    reader.MoveToNextAttribute();
                    int B = Int32.Parse(reader.Value);

                    startColor = Color.FromArgb(A, R, G, B);


                    reader.ReadToFollowing("EndColor");
                    reader.MoveToFirstAttribute();
                    endColor = Color.FromArgb(Int32.Parse(reader.Value), Int32.Parse(reader.Value), Int32.Parse(reader.Value), Int32.Parse(reader.Value));


                    reader.ReadToFollowing("MinVelocityRotation");
                    numericUpDown17.Value = Int32.Parse(reader.ReadElementContentAsString());


                    reader.ReadToFollowing("StartMagnitude");
                    numericUpDown18.Value = Int32.Parse(reader.ReadElementContentAsString());


                    reader.ReadToFollowing("MaxVelocityRotation");
                    numericUpDown26.Value = Int32.Parse(reader.ReadElementContentAsString());


                    reader.ReadToFollowing("EndMagnitude");
                    numericUpDown27.Value = Int32.Parse(reader.ReadElementContentAsString());


                    reader.ReadToFollowing("EmitterType");
                    comboBox1.SelectedItem = reader.ReadElementContentAsString();



                }
            }

        }




        private void panel1_MouseDown_1(object sender, MouseEventArgs e)
        {
            mouseIsDown = true;
        }


        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (mouseIsDown)
            {
                emitterPoint = e.Location;
            }
        }

        private void panel1_MouseUp_1(object sender, MouseEventArgs e)
        {
            mouseIsDown = false;
        }







    }
}
